// axios封装
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError, AxiosPromise } from 'axios'
import router from '@/router/router'

export type ResType<T> = {
  code: number
  msg: string
  data: T
}

export interface MyAxiosInstance extends AxiosInstance {
  <T>(config: AxiosRequestConfig): Promise<ResType<T>>
  // <T>(url: string, config?: AxiosRequestConfig): Promise<ResType<T>>;
}

interface Options {
  // 是否开启取消重复请求, 默认为 true
  cancelDuplicateRequest?: boolean
  // 是否开启loading层效果, 默认为false
  loading?: boolean
  // 是否开启简洁的数据结构响应, 默认为true
  reductDataFormat?: boolean
  // 是否开启接口错误信息展示,默认为true
  showErrorMessage?: boolean
  // 是否开启code不为0时的信息提示, 默认为true
  showCodeMessage?: boolean
  // 是否开启code为0时的信息提示, 默认为false
  showSuccessMessage?: boolean
  // 当前请求使用另外的用户token
  anotherToken?: string
}

type ApiPromise<T = any> = Promise<ResType<T>>

interface anyObj {
  [key: string]: any
}

const pendingMap = new Map()

const createAxios = <T>(axiosConfig: AxiosRequestConfig, options: Options = {}): ApiPromise<T> => {
  const request = axios.create({
    baseURL: 'https://yshxk.com/uat/admin-api/',
    // baseURL: 'https://yshxk.com/admin-api/',
    timeout: 5000,
  })

  options = Object.assign(
    {
      cancelDuplicateRequest: true, // 是否开启取消重复请求, 默认为 true
      loading: false, // 是否开启loading层效果, 默认为false
      reductDataFormat: true, // 是否开启简洁的数据结构响应, 默认为true
      showErrorMessage: true, // 是否开启接口错误信息展示,默认为true
      showCodeMessage: true, // 是否开启code不为1时的信息提示, 默认为true
      showSuccessMessage: false, // 是否开启code为1时的信息提示, 默认为false
      anotherToken: '', // 当前请求使用另外的用户token
    },
    options
  )

  request.interceptors.request.use(config => {
    options.cancelDuplicateRequest && addPending(config)
    // 携带token
    if (config.headers) {
      config.headers['Authorization'] = 'Bearer ' + localStorage.getItem('accessToken')
    }
    return config
  }, error => {
    return Promise.reject(error)
  })

  request.interceptors.response.use(response => {
    removePending(response.config)
    if (response.data) {
      if (response.data.code == 0) {
        // 请求成功
        return options.reductDataFormat ? response.data : response;
      } else if (response.data.code == 401) {
        // 跳转到登录页面
        // window.location.href = '/login'
        router.navigate('/login')
      }
      return options.reductDataFormat ? response.data : response;
    }
    return options.reductDataFormat ? response.data : response;
  }, error => {
    error.config && removePending(error.config)
    return Promise.reject(error) // 错误继续返回给到具体页面
  })

  return request(axiosConfig) as ApiPromise
  // return options.reductDataFormat ? (request(axiosConfig) as ApiPromise) : (request(axiosConfig) as AxiosPromise)
}

/**
 * 储存每个请求的唯一cancel回调, 以此为标识
 */
function addPending(config: AxiosRequestConfig) {
  const pendingKey = getPendingKey(config)
  config.cancelToken =
    config.cancelToken ||
    new axios.CancelToken((cancel) => {
      if (!pendingMap.has(pendingKey)) {
        pendingMap.set(pendingKey, cancel)
      }
    })
}

/**
* 删除重复的请求
*/
const removePending = (config: AxiosRequestConfig) => {
  const pendingKey = getPendingKey(config)
  if (pendingMap.has(pendingKey)) {
    const cancelToken = pendingMap.get(pendingKey)
    cancelToken(pendingKey)
    pendingMap.delete(pendingKey)
  }
}

/**
 * 生成每个请求的唯一key
 */
const getPendingKey = (config: AxiosRequestConfig) => {
  let { data } = config
  const { url, method, params, headers } = config
  if (typeof data === 'string') data = JSON.parse(data) // response里面返回的config.data是个字符串对象
  return [
    url,
    method,
    headers && (headers as anyObj).Authorization ? (headers as anyObj).Authorization : '',
    JSON.stringify(params),
    JSON.stringify(data),
  ].join('&')
}

// const request = axios.create({
//   baseURL: 'https://yshxk.com/admin-api/',
//   timeout: 5000,
// })

// request.interceptors.request.use(config => {
//   // 请求拦截器
//   return config
// }, error => {
//   return Promise.reject(error)
// })

// request.interceptors.response.use(response => {
//   // 2xx范围内的状态码都会触发该函数
//   const res = response.data
//   return res
//   if (res.code == 0) {
//     return res
//   } else {
//     return Promise.reject(res)
//   }
// }, error => {
//   // 超出 2xx 范围的状态码都会触发该函数
//   const res = error.response;
//   if (res.status === 401) {
//     window.location.reload();
//   }
//   return Promise.reject(error)
// })

export {
  createAxios
}